﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Nature.Toolkit.GMix.Generic
{
    [DebuggerDisplay("{ComponentName}")]
    [Serializable]
    public abstract class GenericComponent : IComponent
    {
        #region Private Members

        private GenericExpression m_expression;
        private Dictionary<ILhs, IRhs> m_items = new Dictionary<ILhs, IRhs>();
        private UnitsSet m_units;


        private ILhsSpecies FindLhsSpecies(string speciesID)
        {
            speciesID = speciesID.ToLower();
            return m_items.Keys.OfType<ILhsSpecies>().SingleOrDefault(i => i.SpeciesId.ToLower() == speciesID);
        }


        private ILhsComponent FindLhsComponent(string componentName)
        {
            componentName = componentName.ToLower();
            return m_items.Keys.OfType<ILhsComponent>().SingleOrDefault(i => i.ComponentName.ToLower() == componentName);
        } 

        #endregion

        protected GenericComponent(GenericExpression expression, string componentName, bool isRoot)
        {
            m_expression = expression;
            this.ComponentName = componentName;
            this.DisplayName = componentName;
            this.IsRoot = isRoot;
            m_units = expression.Units;            
        }

        public TemperatureUnits TemperatureUnits
        {
            get { return m_units.TemperatureUnits; }
            set { m_units.TemperatureUnits = value; }
        }

        public PressureUnits PressureUnits
        {
            get { return m_units.PressureUnits; }
            set { m_units.PressureUnits = value; }
        }

        public bool IsMassBased
        {
            get { return m_units.IsMassBased; }
            set { m_units.IsMassBased = value; }
        }

        public double? CompositionScale
        {
            get { return m_units.CompositionScale; }
            set { m_units.CompositionScale = value; }
        }

        #region IComponent Members

        public UnitsSet ActualUnits
        {
            get { return m_units; }
            set { m_units = value; }
        }

        public string ComponentName
        {
            get;
            private set;
        }

        public string DisplayName
        {
            get;
            private set;
        }

        public bool IsRoot
        {
            get;
            private set;
        }

        public IEnumerable<ILhs> LhsSet
        {
            get { return m_items.Keys; }
        }

        public IRhs this[ILhs lhs]
        {
            get { return m_items[lhs]; }
        }

        #endregion

        #region IEquatable<IComponent> Members

        public bool Equals(IComponent other)
        {
            return object.ReferenceEquals(this, other);
        }

        #endregion

        public void RemoveSpecies(string speciesID)
        {
            var key = FindLhsSpecies(speciesID);
            if (key != null) { m_items.Remove(key); }
        }

        public void RemoveComponent(string componentName)
        {
            var key = FindLhsComponent(componentName);
            if (key != null) { m_items.Remove(key); }
        }        

        public void SetSpecies(string speciesId, double? value)
        {
            ILhsSpecies lhs = FindLhsSpecies(speciesId) ?? Lhs.Species(speciesId);
            IRhs rhs = Rhs.Value(value);
            m_items[lhs] = rhs;
        }

        public void SetComponent(string componentName, double? value)
        {
            ILhsComponent lhs = FindLhsComponent(componentName) ?? Lhs.Component(componentName);
            IRhs rhs = Rhs.Value(value);
            m_items[lhs] = rhs;
        }

        public void SetSpecies(string speciesId, string parameterName, IEnumerable<double> data)
        {
            ILhsSpecies lhs = FindLhsSpecies(speciesId) ?? Lhs.Species(speciesId);
            IRhs rhs = Rhs.Enumerable(parameterName, data);
            m_items[lhs] = rhs;
        }

        public void SetComponent(string componentName, string parameterName, IEnumerable<double> data)
        {
            ILhsComponent lhs = FindLhsComponent(componentName) ?? Lhs.Component(componentName);
            IRhs rhs = Rhs.Enumerable(parameterName, data);
            m_items[lhs] = rhs;
        }

        public void SetTemperature(double? rhs)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsTemperature);
            if (lhs != null)
            {
                m_items[lhs] = Rhs.Value(rhs);
                return;
            }
            m_items.Add(Lhs.Temperature, Rhs.Value(rhs));
        }

        public void SetTemperature(string parameterName, IEnumerable<double> data)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsTemperature);
            if (lhs != null)
            {
                m_items[lhs] = Rhs.Enumerable(parameterName, data);
                return;
            }
            m_items.Add(Lhs.Temperature, Rhs.Enumerable(parameterName, data));
        }

        public void SetTemperatureBase(double? rhs)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsTemperatureBase) ?? Lhs.TemperatureBase;
            m_items[lhs] = Rhs.Value(rhs);
        }

        public void SetTemperatureBase(string parameterName, IEnumerable<double> data)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsTemperatureBase) ?? Lhs.TemperatureBase;
            m_items[lhs] = Rhs.Enumerable(parameterName, data);
        }

        public void SetPressure(double? rhs)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsPressure);
            if (lhs != null)
            {
                m_items[lhs] = Rhs.Value(rhs);
                return;
            }
            m_items.Add(Lhs.Pressure, Rhs.Value(rhs));
        }

        public void SetPressure(string parameterName, IEnumerable<double> data)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsPressure);
            if (lhs != null)
            {
                m_items[lhs] = Rhs.Enumerable(parameterName, data);
                return;
            }
            m_items.Add(Lhs.Pressure, Rhs.Enumerable(parameterName, data));
        }

        public void SetPressureBase(double? rhs)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsPressureBase) ?? Lhs.PressureBase;
            m_items[lhs] = Rhs.Value(rhs);
        }

        public void SetPressureBase(string parameterName, IEnumerable<double> data)
        {
            m_items.Add(Lhs.PressureBase, Rhs.Enumerable(parameterName, data));
        }

        public void SetCompressionRatio(double? rhs)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsCompressionRatio);
            if (lhs != null)
            {
                m_items[lhs] = Rhs.Value(rhs);
                return;
            }
            m_items.Add(Lhs.CompressionRatio, Rhs.Value(rhs));
        }

        public void SetCompressionRatio(string parameterName, IEnumerable<double> data)
        {
            m_items.Add(Lhs.CompressionRatio, Rhs.Enumerable(parameterName, data));
        }

        public void SetMachNumber(double? rhs)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsMachNumber) ?? Lhs.MachNumber;
            m_items[lhs] = Rhs.Value(rhs);
        }

        public void SetMachNumber(string parameterName, IEnumerable<double> data)
        {
            var lhs = m_items.Keys.FirstOrDefault(i => i is ILhsMachNumber) ?? Lhs.MachNumber;
            m_items[lhs] = Rhs.Enumerable(parameterName, data);
        }

        public void SetEquivalenceRatio(double? value)
        {
            ILhs lhs = m_items.Keys.FirstOrDefault(i => i is ILhsEquivalenceRatio) ?? Lhs.EquivalenceRatio;
            if (m_items.ContainsKey(lhs) && value == null) 
            {
                m_items.Remove(lhs);
                return;
            }
            m_items[lhs] = Rhs.Value(value);
        }

        public void SetMixtureFraction(double value)
        {
            m_items.Add(Lhs.MixtureFraction, Rhs.Value(value));
        }

        public void SetMixtureFraction(string parameterName, IEnumerable<double> values)
        {
            ILhs lhs = m_items.Keys.FirstOrDefault(i => i is ILhsMixtureFraction) ?? Lhs.MixtureFraction;
            m_items[lhs] = Rhs.Enumerable(parameterName, values);
        }
    }
}
